#include "BacInetSocket.h"

using namespace com::fiill;

BacInetSocket::BacInetSocket(SOCKIDTYPE id) :mId(id){}

BacInetSocket::~BacInetSocket() {
    isExiting = 1;
    if (serverFd > 0) {
        close(serverFd);
        serverFd = -1;
    }
}
    
BacInetSocketServer::BacInetSocketServer(SOCKIDTYPE port, CommandProcessorFuncType handler, int flag):
          BacInetSocket(port), mHandler(handler), mDefaultFlag(flag){
    LOGI("BacInetSocketServer Constructor, flag=%d, bind port:%d", flag, port);
}

int BacInetSocketServer::service_listen() {
    int ret = 0;

    serverFd = socket(AF_INET,SOCK_STREAM, 0);
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    //local.sin_addr.s_addr = inet_addr("192.168.1.1");
    local.sin_addr.s_addr = htonl(INADDR_ANY);
    local.sin_port = htons(mId);

    int reuse = 1;
    ret = setsockopt( serverFd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse) );

    ret = bind(serverFd,(struct sockaddr*)&local, sizeof(local));
    if (ret < 0)  {
        LOGE("bind() failed, serverFd=%d", serverFd);
        return ret;
    }


    ret = listen(serverFd, MAX_B_CMD_LISTEN_CLIENT_Fd_NUM);
    LOGD("listen() Fd>> %d <<<  status=%d", serverFd, ret);
    if (ret < 0) {
        return ret;
    }
    return ret;
}

void* exec_thread(void* arg) {
    int ret = 0;
    int sockFd = ((threadArgType*)arg)->socketFd;
    CommandProcessorFuncType handler = ((threadArgType*)arg)->handler;
    BacInetSocketServer* _this = 
        (BacInetSocketServer*)(((threadArgType*)arg)->pThis);
    while (ret >= 0) {
        ret = _this->exec_send_once(sockFd, handler);
        usleep(12*1024);
        //if (! ( _this->getFlag() & O_NONBLOCK)) close(sockFd);
    }
    return (void*)(long)ret;
}

int BacInetSocketServer::exec_send_once(int clientFd, CommandProcessorFuncType handler) {
    int ret = 0, size = -1;
    char recvBuf[MAX_CMD_LEN + 1];
    char* respBuf;
    memset(recvBuf, 0, sizeof(recvBuf));
    size = BacInetSocket::receive_data(clientFd, recvBuf, MAX_CMD_LEN);
    if(0 == size) {
        LOGW("client %d read 0 size data, exit.", clientFd);
        if (! (this->getFlag() & O_NONBLOCK)) {
            close(clientFd);
        }
        return ERROR_SOCKET_CLOSED;
    } else if(size > 0) {
        respBuf = (char*)malloc(MAX_BUFF_SIZE + 1);
        if(NULL == respBuf) return -3;
        memset(respBuf, 0, MAX_BUFF_SIZE + 1);
        respBuf[0] = (char)clientFd;  // Used to print the fd in process function
        ret = ((CommandProcessorFuncType)handler)(recvBuf, respBuf, MAX_BUFF_SIZE);
        if(strlen(respBuf) == 0){
            sprintf(respBuf,"%d", ret);  //use function ret as response data
        }
        if (strlen(respBuf) > 0) {
            LOGI("response to fd(%d):\n%s", clientFd, respBuf);
        }
        ret = BacInetSocket::send_data(clientFd, respBuf, strlen(respBuf));
        if (ret < 0) {
            close(clientFd);
        }
        free(respBuf);
    } else if(size < 0) {
        LOGE("Error[%d] when receiving Data:%s.\n", errno, strerror(errno));
        ret  = ERROR_SOCKET_CLOSED;
    }
    return ret;
}

int BacInetSocket::send_data(int fd, const char* buffer, int len) {
    int ret;
    ret = send(fd, buffer, len, 0);
    if (ret < 0) {
        LOGE("send() to [%d] failed", fd);
    }
    return ret;
}

int BacInetSocket::receive_data(int fd, const char * buffer, int max_len) {
    return recv(fd, (void*)buffer, max_len, 0);
}

int BacInetSocketServer::processing() {
    int clientFd = -1;
    pthread_t tid;

    while (!isExiting) {
        clientFd = accept(get_service_fd(), NULL, NULL);
        LOGD("accept() fd:%d ,flag=%d", clientFd, mDefaultFlag);
        if (clientFd > 0 && NULL != mHandler) {
            threadArgType arg;
            arg.pThis = (void*)this;
            arg.socketFd = clientFd;
            arg.handler = mHandler;
            if (pthread_create(&tid, NULL, exec_thread, (void*)&arg)) {
                close(clientFd);
            }
        }
        usleep(12*1024);
    }
    return 0;
}
